#pragma once
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/types.h>
#include "Comm.hpp"
#include <string>
// 等会联系完再把共享内存封装起来
const int gdefauted = -1;
const std::string pathname = ".";
const int projid = 123;
const int gsize = 4096;
#define USER "user"
#define CREATER "creater"
const int gmode = 0666;

// 可以把下面的封装进行跟深层次的封装
class shm
{
private:
    // 为了私密性，所以把一些特定的函数隐藏起来，避免对共享内存的破坏
    void Creater(int flg)
    {
        _shmid = shmget(_key, _size, flg);
        if (_shmid < 0)
            ERR_EXIT("shmget");
        printf("shmid : %d\n", _shmid);
    }

    void CREAT()
    {
        Creater(IPC_CREAT | IPC_EXCL | gmode);
    }

    // 建立虚拟内存空间和物理内存空间的练习
    void ATTACH()
    {
        start_mem = shmat(_shmid, nullptr, 0);
        if ((long long)start_mem < 0)
            ERR_EXIT("shmat");
        // std :: cout << "shmat success" << std :: endl;
    }

    void READ(int flg)
    {
        _shmid = shmget(_key, _size, flg);
        if (_shmid < 0)
            ERR_EXIT("shmget");
        printf("shmid : %d\n", _shmid);
    }

    void GET()
    {
        READ(IPC_CREAT | gmode);
    }

    void DETACH()
    {
        // 下面这个函数的作用就是把虚拟空间和内存之间的练习删掉
        int n = shmdt(start_mem);
        if (n == 0)
        {
            printf("shmdo success\n");
        }
    }

    // 关闭共享内存的操作
    void Destoy()
    {
        DETACH();
        if (user_type == CREATER)
        {
            int n = shmctl(_shmid, IPC_RMID, nullptr); // 这个函数可以删掉共享内存
            if (n == 0)
                std ::cout << "删除成功" << std ::endl;
            else
                std ::cout << "删除失败" << std ::endl;
        }
    }

public:
    shm(const std ::string &pathname, const int projid, const std ::string &username)
        : _shmid(gdefauted),
          _size(gsize),
          start_mem(nullptr),
          user_type(username)
    {
        _key = ftok(pathname.c_str(), projid);
        if (_key < 0)
        {
            ERR_EXIT("ftok");
        }
        if (username == CREATER)
        {
            CREAT();
        }
        else if(username == USER)
        {
            GET();
        }
        ATTACH();
    }

    void *getmem()
    {
        return start_mem;
    }
    ~shm()
    {
        std ::cout << user_type << std ::endl;
        if(user_type == CREATER)
        {
            Destoy();
        }
    }

private:
    int _shmid; // 创建共享内存时返回的id
    key_t _key;
    int _size;
    void *start_mem; // 虚拟空间的起始地址
    std ::string user_type;
};